﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Media;
using System.Drawing;
using System.Linq;
using System.Text;
using System.IO;
using System.Windows.Forms;
using System.Threading;
using System.Security.Cryptography;
using System.Management;
using System.Runtime;
using System.Runtime.InteropServices;
using Microsoft.DirectX;
using Microsoft.DirectX.DirectSound;

namespace STT
{
    public partial class Form1 : Form
    {
        //声明代理
        public delegate void boolDelegate(bool b);
        public delegate void intDelegate(int i);
        public delegate void strDelegate(string s );

        public string strRecSaveFile = string.Empty;//文件保存路径
        public Notify myNotify = null;//缓冲区提示事件
        //private FileStream fsWav = null;//保存的文件流
        public int iNotifyNum = 16;//通知的个数
        public int iBufferOffset = 0;//本次数据起始点， 上一次数据的终点。
        public int iSampleSize = 0;//所采集到的数据大小
        public int iNotifySize = 0;//通知所在区域大小
        public int iBufferSize = 0;//缓冲区大小
        public BinaryWriter mWriter;
        public Capture capture = null;//捕捉设备对象
        public CaptureBuffer capturebuffer = null;//捕捉缓冲区
        //private AutoResetEvent notifyEvent = null;
        public AutoResetEvent notifyEvent = null;
        public Thread notifyThread = null;
        public WaveFormat mWavFormat;//PCM格式

        ///// <summary>
        ///// 关于wave in caps的详细说明
        ///// http://msdn.microsoft.com/en-US/library/windows/desktop/dd743839(v=vs.85).aspx
        ///// </summary>
        //[StructLayout(LayoutKind.Sequential)]//, Pack = 4)]
        //public struct WaveInCaps
        //{
        //    public ushort wMid;
        //    public ushort wPid;
        //    public uint vDriverVersion;
        //    //[MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)]
        //    //public char[] szPname;
        //    [MarshalAs(UnmanagedType.ByValTStr,SizeConst = 32)]
        //    public string szPname;
        //    public uint dwFormats;
        //    public ushort wChannels;
        //    public ushort wReserved1;
        //}

        ///// <summary>
        ///// 关于wave out caps的详细说明
        ///// http://msdn.microsoft.com/en-us/dd743855(v=vs.85)
        ///// </summary>
        //[StructLayout(LayoutKind.Sequential)]//, Pack = 4)]
        //public struct WAVEOUTCAPS
        //{
        //    //制造商ID
        //    public ushort wMid;
        //    //产品ID
        //    public ushort wPid;
        //    //版本号，高字节是主，低字节是次
        //    public uint vDriverVersion;
        //    //产品名称
        //    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
        //    public string szPname;
        //    //支持的格式
        //    public uint dwFormats;
        //    //单声道(1)还是立体声(2)
        //    public ushort wChannels;
        //    //其他
        //    public ushort wReserved1;
        //    //可选的参数
        //    public uint dwSupport;
        //}

        ////声明使用winmm.dll 获取 波形输出设备的数量
        //[DllImport("winmm.dll")]
        //public static extern uint waveOutGetNumDevs();

        //[DllImport("winmm.dll")]
        //public static extern uint waveOutGetDevCaps(IntPtr hwo, ref WAVEOUTCAPS pwoc, uint cbwoc);

        ////声明使用winmm.dll 获取 波形输入设备的数量
        //[DllImport("winmm.dll")]
        //public static extern uint waveInGetNumDevs();

        //[DllImport("winmm.dll")]
        //public static extern uint waveInGetDevCaps(IntPtr hwo, ref WaveInCaps pwoc, uint cbwoc);

        public bool runningFlag = false;
        //Thread backwork = null;

        //主窗体
        public Form1()
        {
            InitializeComponent();

            //更改停止按钮
            btnStopStatChange(false);
            //更改进度条最大值
            progressBar1.Maximum = 2147483647;
            //刷新声卡列表
            getSoundDevice();
        }

        //更改运行标志
        public void runFlagChange(bool b)
        {
            if (this.InvokeRequired)
            {
                this.BeginInvoke(new boolDelegate(runFlagChange),b);
            }
            else
            {
                runningFlag = b;
            }
        }

        //更改运行按钮状态
        public void btnRunStatChange(bool b)
        {
            if (this.InvokeRequired)
            {
                this.BeginInvoke(new boolDelegate(btnRunStatChange), b);
            }
            else
            {
                btnRun.Enabled = b;
            }
        }

        //更改停止按钮状态
        public void btnStopStatChange(bool b)
        {
            if (this.InvokeRequired)
            {
                this.BeginInvoke(new boolDelegate(btnStopStatChange), b);
            }
            else
            {
                btnStop.Enabled = b;
            }
        }

        //更改进度条状态
        public void progressBarStatChange(int i)
        {
            if (this.InvokeRequired)
            {
                this.BeginInvoke(new intDelegate(progressBarStatChange), i);
            }
            else
            {
                this.progressBar1.Value = i;
            }
        }

        //追加reachtextbox内容
        public void appendReachTextBox(string s)
        {
            if (this.InvokeRequired)
            {
                this.BeginInvoke(new strDelegate(appendReachTextBox), s);
            }
            else
            {
                this.richTextBox1.AppendText(s + "\r\n");
                //this.richTextBox1.Text = s;
            }
        }

        //更改reachtextbox内容
        public void changeReachTextBox(string s)
        {
            if (this.InvokeRequired)
            {
                this.BeginInvoke(new strDelegate(changeReachTextBox), s);
            }
            else
            {
                //this.richTextBox1.AppendText(s + "\n\r");
                this.richTextBox1.Text = s;
            }
        }

        //音频处理线程
        public void running(object devguid)
        {
            //Random random = new Random(rndSeed());
            //SetWaveFormat(44100, 20, 2);
            CreateCaputerDevice((Guid) devguid);
            CreateCaptureBuffer();
            CreateNotification();

            try
            {
                while (runningFlag)
                {
                    //运行音频处理
                    //int rnd = random.Next();
                    //progressBarStatChange(rnd);
                    ////changeReachTextBox(rnd.ToString());
                    Thread.Sleep(50);

                    //采集声音
                    //http://www.cnblogs.com/stg609/archive/2008/10/24/1318931.html
                    //http://www.cnblogs.com/stg609/archive/2008/11/19/1334544.html
                    RecoData();
                }
            }
            catch(Exception e)
            {
                MessageBox.Show("running,while\n\r" + e.ToString());
            }

            //退出线程前，把运行按钮恢复
            btnRunStatChange(true);
            btnStopStatChange(false);
        }

        //点击运行按钮
        public void btnRun_Click(object sender, EventArgs e)
        {
            //更改运行按钮状态
            btnRunStatChange(false);
            //更改运行标志状态
            runFlagChange(true);
            //更改停止按钮状态
            btnStopStatChange(true);

            //启动处理线程
            ParameterizedThreadStart parThread = new ParameterizedThreadStart(running);
            //Thread backwork = new Thread(new ThreadStart(parThread));
            Thread backwork = new Thread(parThread);
            backwork.IsBackground = true;
            string str = (string)cBoxWaveIn.SelectedValue;
            Guid myid = new Guid(str);
            backwork.Start((object)myid);

        }

        //点击停止按钮
        public void btnStop_Click(object sender, EventArgs e)
        {
            //btnRunStatChange(true);
            runFlagChange(false);
            //btnStopStatChange(false);
        }
        
        public void btnGetSoundDevice_Click(object sender, EventArgs e)
        {
            getSoundDevice();
        }

        public void getSoundDevice()
        {
            #region directX
            //枚举音频捕捉设备
            CaptureDevicesCollection capDevs = new CaptureDevicesCollection();
            if (capDevs.Count > 0)
            {
                DataTable dt = new DataTable();
                dt.Columns.Add("deviceID");
                dt.Columns.Add("deviceName");
                for (int i = 0; i < capDevs.Count; i++)
                {
                    DataRow dr = dt.NewRow();
                    dr[0] = capDevs[i].DriverGuid;
                    dr[1] = capDevs[i].Description.ToString();
                    dt.Rows.Add(dr);
                }
                cBoxWaveIn.DisplayMember = "deviceName";
                cBoxWaveIn.ValueMember = "deviceID";
                cBoxWaveIn.DataSource = dt;
            }

            //枚举音频播放设备
            DevicesCollection devs = new DevicesCollection();
            if (devs.Count > 0)
            {
                DataTable dt = new DataTable();
                dt.Columns.Add("deviceID");
                dt.Columns.Add("deviceName");
                for (int i = 0; i < devs.Count; i++)
                {
                    DataRow dr = dt.NewRow();
                    dr[0] = devs[i].DriverGuid;
                    dr[1] = devs[i].Description.ToString();
                    dt.Rows.Add(dr);
                }
                cBoxWaveOut.DisplayMember = "deviceName";
                cBoxWaveOut.ValueMember = "deviceID";
                cBoxWaveOut.DataSource = dt;
            }
            cBoxWaveIn_SelectionChangeCommitted();
            cBoxWaveOut_SelectionChangeCommitted();
            #endregion
        }

        public void cBoxWaveIn_SelectionChangeCommitted(object sender, EventArgs e)
        {
            appendReachTextBox("text:" + cBoxWaveIn.Text.ToString());
            appendReachTextBox("value:" + cBoxWaveIn.SelectedValue.ToString());
        }
        public void cBoxWaveIn_SelectionChangeCommitted()
        {
            appendReachTextBox("text:" + cBoxWaveIn.Text.ToString());
            appendReachTextBox("value:" + cBoxWaveIn.SelectedValue.ToString());
        }

        public void cBoxWaveOut_SelectionChangeCommitted(object sender, EventArgs e)
        {
            appendReachTextBox("text:" + cBoxWaveOut.Text.ToString());
            appendReachTextBox("value:" + cBoxWaveOut.SelectedValue.ToString());
        }
        public void cBoxWaveOut_SelectionChangeCommitted()
        {
            appendReachTextBox("text:" + cBoxWaveOut.Text.ToString());
            appendReachTextBox("value:" + cBoxWaveOut.SelectedValue.ToString());
        }





        //函数--设置声音格式
        public WaveFormat SetWaveFormat()
        {
            WaveFormat format = new WaveFormat();
            SetWaveFormat(44100, 16, 2);
            return format;
        }
        public WaveFormat SetWaveFormat(int samplerate, short bits, short channels)
        {
            WaveFormat format = new WaveFormat();
            //声音的格式，通常使用wave_format_pcm
            format.FormatTag = WaveFormatTag.Pcm;
            //采样率，单位赫兹，典型值：11025、22050、44100 Hz
            format.SamplesPerSecond = samplerate;
            //每个采样点的数据长度：8—bit，16-bit
            format.BitsPerSample = bits;
            //声道
            format.Channels = channels;
            //采样点的字节数
            format.BlockAlign = (short)(format.Channels * (format.BitsPerSample / 8));
            //传输速率，每秒数据流量
            format.AverageBytesPerSecond = format.BlockAlign * format.SamplesPerSecond;
            return format;
        }

        //创建采集设备
        public void CreateCaputerDevice(Guid devGuid)
        {
            capture = new Capture(devGuid);
        }

        /// <summary>
        /// 创建捕捉缓冲区对象
        /// </summary>
        public void CreateCaptureBuffer()
        {
            //想要创建一个捕捉缓冲区必须要两个参数：缓冲区信息（描述这个缓冲区中的格式等），缓冲设备。
            WaveFormat mWavFormat = SetWaveFormat();
            CaptureBufferDescription bufferdescription = new CaptureBufferDescription();
            bufferdescription.Format = mWavFormat;//设置缓冲区要捕捉的数据格式
            iNotifySize = mWavFormat.AverageBytesPerSecond / iNotifyNum;//1秒的数据量/设置的通知数得到的每个通知大小小于0.2s的数据量，话音延迟小于200ms为优质话音
            iBufferSize = iNotifyNum * iNotifySize;
            bufferdescription.BufferBytes = iBufferSize;
            bufferdescription.ControlEffects = true;
            bufferdescription.WaveMapped = true;
            try
            {
                capturebuffer = new CaptureBuffer(bufferdescription, capture);//建立设备缓冲区对象
            }
            catch(Exception e)
            {
                MessageBox.Show("CreateCaptureBuffre()\n" + e.ToString());
            }

        }

        //设置通知
        public void CreateNotification()
        {
            BufferPositionNotify[] bpn = new BufferPositionNotify[iNotifyNum];//设置缓冲区通知个数
            //设置通知事件
            notifyEvent = new AutoResetEvent(false);
            notifyThread = new Thread(RecoData);//通知触发事件
            notifyThread.IsBackground = true;
            notifyThread.Start();

            try
            {
                for (int i = 0; i < iNotifyNum; i++)
                {
                    bpn[i].Offset = iNotifySize + i * iNotifySize - 1;//设置具体每个的位置
                    bpn[i].EventNotifyHandle = notifyEvent.Handle;
                }
                myNotify = new Notify(capturebuffer);
                myNotify.SetNotificationPositions(bpn);
            }
            catch(Exception e)
            {
                MessageBox.Show("create notificatiion\n" + e.ToString());
            }

        }

        //线程中的事件
        public void RecoData()
        {
            while (this.runningFlag)
            {
                // 等待缓冲区的通知消息
                notifyEvent.WaitOne(Timeout.Infinite, true);
                // 录制数据
                //RecordCapturedData(Client, epServer);
                RecordCapturedData();
            }
        }

        //真正转移数据的事件，其实就是把数据传送到网络上去。
        //private void RecordCapturedData(Socket Client, EndPoint epServer)
        //{
        //    byte[] capturedata = null;
        //    int readpos = 0, capturepos = 0, locksize = 0;
        //    capturebuffer.GetCurrentPosition(out capturepos, out readpos);
        //    locksize = readpos - iBufferOffset;//这个大小就是我们可以安全读取的大小
        //    if (locksize == 0)
        //    {
        //        return;
        //    }
        //    if (locksize < 0)
        //    {//因为我们是循环的使用缓冲区，所以有一种情况下为负：当文以载读指针回到第一个通知点，而Ibuffeoffset还在最后一个通知处
        //        locksize += iBufferSize;
        //    }
        //    capturedata = (byte[])capturebuffer.Read(iBufferOffset, typeof(byte), LockFlag.FromWriteCursor, locksize);
        //    //capturedata = g729.Encode(capturedata);//语音编码
        //    try
        //    {
        //        Client.SendTo(capturedata, epServer);//传送语音
        //    }
        //    catch
        //    {
        //        throw new Exception();
        //    }
        //    iBufferOffset += capturedata.Length;
        //    iBufferOffset %= iBufferSize;//取模是因为缓冲区是循环的。
        //}
        public void RecordCapturedData()
        {
            byte[] capturedata = null;
            int readpos = 0, capturepos = 0, locksize = 0;
            capturebuffer.GetCurrentPosition(out capturepos, out readpos);
            locksize = readpos - iBufferOffset;//这个大小就是我们可以安全读取的大小
            if (locksize == 0)
            {
                return;
            }
            if (locksize < 0)
            {//因为我们是循环的使用缓冲区，所以有一种情况下为负：当文以载读指针回到第一个通知点，而Ibuffeoffset还在最后一个通知处
                locksize += iBufferSize;
            }
            capturedata = (byte[])capturebuffer.Read(iBufferOffset, typeof(byte), LockFlag.FromWriteCursor, locksize);
            //capturedata = g729.Encode(capturedata);//语音编码
            try
            {
                //Client.SendTo(capturedata, epServer);//传送语音
            }
            catch
            {
                throw new Exception();
            }
            iBufferOffset += capturedata.Length;
            iBufferOffset %= iBufferSize;//取模是因为缓冲区是循环的。
        }
    }
}
